home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / bipl.zip / PROCS.ZIP / SENTEN1.ICN < prev    next >
Text File  |  1992-09-28  |  9KB  |  228 lines

  1. ############################################################################
  2. #
  3. #    File:     sentence.icn
  4. #
  5. #    Subject:  Procedures to generate sentences
  6. #
  7. #    Author:   Peter A. Bigot
  8. #
  9. #    Date:     September 12, 1990
  10. #
  11. ###########################################################################
  12. #
  13. #
  14. # The following rules describe what a 'sentence' is.
  15. # * A sentence begins with a capitol letter.
  16. # * A sentence ends with one or more of '.!?', subject to other
  17. #   constraints.
  18. # * If a period is immediately followed by:
  19. #   - a digit
  20. #   - a letter
  21. #   - one of ',;:'
  22. #   it is not a sentence end.
  23. # * If a period is followed (with intervening space) by a lower case
  24. #   letter, it is not a sentence end (assume it's part of an abbreviation).
  25. #
  26. # * The sequence '...' does not end a sentence.  The sequence '....' does.
  27. # * If a sentence end character appears after more opening parens than
  28. #   closing parens in a given sequence, it is not the end of that
  29. #   particular sentence. (I.e., full sentences in a parenthetical remark
  30. #   in an enclosing sentence are considered part of the enclosing
  31. #   sentence.  Their grammaticality is in question, anyway.) (It also
  32. #   helps with attributions and abbreviations that would fail outside
  33. #   the parens.)
  34. #
  35. # * No attempt is made to ensure balancing of double-quoted (") material.
  36. # * When scanning for a sentence start, material which does not conform is
  37. #   discarded.
  38. # * Corollary: Quotes or parentheses which enclose a sentence are not
  39. #   considered part of it.
  40. # * An end-of-line on input is replaced by a space unless the last
  41. #   character of the line is 'a-' (where 'a' is any letter), in which case
  42. #   the hyphen is deleted.
  43. #
  44. # * Leading and trailing space (tab, space, newline) chars are removed
  45. #   from each line of the input.
  46. #
  47. # * If a blank line is encountered on input while scanning a sentence,
  48. #   the scan is aborted and search for a new sentence begins (rationale:
  49. #   ignore section and chapter headers separated from text by newlines).
  50. #
  51. # * Most titles before names would fail the above constraints.  They are
  52. #   special-cased.
  53. #
  54. # * This does NOT handle when a person uses their middle initial.  To do
  55. #   so would rule out sentences such as 'It was I.',  Six of one, half-dozen
  56. #   of the other--I made my choice.
  57. #
  58. # * Note that ':' does not end a sentence.  This is a stylistic choice,
  59. #   and can be modified by simply adding ':' to sentend below.
  60. #
  61.  
  62. # sentence(f) -- generate English sentences encountered in given file
  63. procedure sentence (infile)
  64.    local
  65.       line,                     # Line read from input, beginning could be sent.
  66.       sentence,                 # A possible sentence
  67.       lstend,                   # Position in line of last checked sentence end
  68.       possentp,                 # Boolean: non-null if line mod context =  sent.
  69.       spaceskip,                # Spaces betwen EOSent and next char (context)
  70.       nextch,                   # Next char after EOSent
  71.       cnt                       # Balanced count of parens in possible sent.
  72.    static
  73.       sentend,                  # Cset for sentence end chars
  74.       wspace,                   # White space characters
  75.       noperend,                 # Chars which, after period, don't end sentence
  76.       titles                    # Titles that can appear before names.
  77.    initial {
  78.       sentend := '.?!'          # Initial value for sentend
  79.       wspace := ' \t\n'         # Space chars
  80.       noperend := &digits ++ &letters ++ ',:;' # No-end after period chars
  81.       titles := ["Mr.", "Mrs.", "Ms.", "Dr.", "Prof.", "Pres."]
  82.       }
  83.  
  84.    line := ""
  85.    # Repeat scanning for and suspending sentences until input fails.
  86.    repeat {
  87.       # Try to find the start of a sentence in the current input string.
  88.       # If there are none, read more from file; fail if file exhausted.
  89.       # Trim trailing space from line (leading skipped by sentence start)
  90.       while not (line ?:= (tab (upto (&ucase)) & tab (0))) do {
  91.          line := trim (read (infile), wspace) | fail
  92.          }
  93.  
  94.       # Find the sentence end.  If there's no viable candidate, read more
  95.       # from input.  Set the last end position to the first char in the
  96.       # sentence.
  97.       lstend := 1
  98.       possentp := &null
  99.       repeat {
  100.          line ? {
  101.             # Skip up to new stuff (scanned in previous lines).
  102.             sentence := tab (lstend)
  103.             while sentence ||:= tab (upto (sentend)) do {
  104.                sentence ||:= tab (many (sentend))
  105.                
  106.                # Verify end-of-sentence.  Assume it doesn't pass.
  107.                possentp := &null
  108.                
  109.                # Check for sentence end conformance.  See what follows it: put
  110.                # that in nextch, and the intervening space before it in
  111.                # spaceskip.
  112.                # Note hack to scan in remainder of line w/o changing &pos.
  113.                nextch := &null
  114.                every tab (0) ? {
  115.                   spaceskip := tab (many (wspace)) | ""
  116.                   nextch := move (1)
  117.                   }
  118.                   
  119.                if /nextch then {
  120.                   # Don't have enough context to ensure a proper sentence end.
  121.                   # Read more, but let readers know that this could be a
  122.                   # sentence end (e.g., in case of EOF on input).
  123.                   possentp := 1
  124.                   break
  125.                   }
  126.                
  127.                # Save position of last checked sentence end, so we don't try to
  128.                # recheck this one.
  129.                lstend := &pos
  130.                
  131.                # .<noperend> doesn't end a sentence.
  132.                if (sentence [-1] == '.' &
  133.                    spaceskip == "" &
  134.                    any (noperend, nextch)) then {
  135.                   next
  136.                   }
  137.                
  138.                # .<spc><lcase> doesn't end sentence
  139.                if (sentence [-1] == '.' &
  140.                    any (&lcase, nextch)) then {
  141.                   next
  142.                   }
  143.  
  144.                # ... doesn't end sentence. .... does.
  145.                if (sentence [-3:0] == "..." &
  146.                    sentence [-4] ~== ".") then {
  147.                   next
  148.                   }
  149.  
  150.                # Number of ')' must be >= number '(' in sentence.
  151.                sentence ? {
  152.                   cnt := 0
  153.                   while tab (upto ('()')) do {
  154.                      if ="(" then {
  155.                         cnt +:= 1
  156.                         }
  157.                      else {
  158.                         =")"
  159.                         cnt -:= 1
  160.                         }
  161.                      }
  162.                   }
  163.                if (cnt > 0) then {
  164.                   next
  165.                   }
  166.  
  167.                # Special case titles that appear before names (otherwise look
  168.                # like sentence ends).
  169.                every t := ! titles do {
  170.                   if (t == sentence [- *t:0]) then {
  171.                      # Break every, next in sentence-end search repeat
  172.                      break next
  173.                      }
  174.                   }
  175.  
  176.                # This is a sentence.  Replace the line with what follows the
  177.                # sentence, and break out of the sentence-end-search loop.
  178.                line := tab (0)
  179.                break break
  180.                }
  181.             }
  182.          # There is no valid sentence end so far.  Remove a trailing hyphen
  183.          # from the current line, or add a word-separating space.
  184.          if line [-1] == '-' & any (&letters, line [-2]) then {
  185.             line := line [1:-1]
  186.             }
  187.          else {
  188.             line ||:= " "
  189.             }
  190.  
  191.          # Read another line.  If can't, then fail--but suspend sentence first
  192.          # if it _could_ be a sentence end.  Trim leading and trailing spaces
  193.          # from the new line--if it's empty, toss the line so far and restart;
  194.          # otherwise, tack it onto the end of the current line.
  195.          if not (newline := read (infile)) then {
  196.             if \possentp then {
  197.                suspend (sentence)
  198.                }
  199.             fail
  200.             }
  201.          if any (wspace, newline) then {
  202.             newline ?:= (tab (many (wspace)), tab (0))
  203.             }
  204.          newline := trim (newline, wspace)
  205.          if (*newline = 0) then {
  206.             if \possentp then {
  207.                suspend (sentence)
  208.                }
  209.             line := ""
  210.             # Break EOS check, next beginning-of-sent scan
  211.             break next
  212.             }
  213.          line ||:= newline
  214.          }
  215.  
  216.       # Suspend the sentence, then loop back for more.
  217.       suspend sentence
  218.       }
  219.    end # procedure sentence
  220.